package com.ev.asl.service.impl;

import com.alibaba.fastjson.JSONArray;
import com.ev.apis.model.DsResultResponse;
import com.ev.asl.constant.AslConstant;
import com.ev.asl.dao.MoldingBarcodeDao;
import com.ev.asl.domain.AslBarCodeDO;
import com.ev.asl.domain.MoldingBarcodeDO;
import com.ev.asl.service.AslBarCodeService;
import com.ev.asl.service.MoldingBarcodeService;
import com.ev.asl.vo.*;
import com.ev.custom.domain.MaterielDO;
import com.ev.custom.service.MaterielService;
import com.ev.framework.utils.DateUtils;
import com.ev.framework.utils.StringUtils;
import com.ev.mes.domain.BomDO2;
import com.ev.mes.domain.ProductionPlanDO;
import com.ev.mes.service.ProductionPlanService;
import com.ev.report.vo.PointVO;
import com.google.common.collect.Maps;
import lombok.Synchronized;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.lang3.tuple.Pair;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Service;

import java.math.BigDecimal;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.*;
import java.util.stream.Collectors;

import com.ev.framework.utils.R;
import org.springframework.util.ObjectUtils;


@Service
@Slf4j
public class MoldingBarcodeServiceImpl implements MoldingBarcodeService {
    @Autowired
    private MoldingBarcodeDao moldingBarcodeDao;
    @Autowired
    private AslBarCodeService aslBarCodeService;


    @Override
    public MoldingBarcodeDO get(Long id) {
        return moldingBarcodeDao.get(id);
    }

    @Override
    public List<MoldingBarcodeDO> list(Map<String, Object> map) {
        return moldingBarcodeDao.list(map);
    }

    @Override
    public int count(Map<String, Object> map) {
        return moldingBarcodeDao.count(map);
    }

    @Override
    public int save(MoldingBarcodeDO moldingBarcode) {
        return moldingBarcodeDao.save(moldingBarcode);
    }

    @Override
    public int update(MoldingBarcodeDO moldingBarcode) {
        return moldingBarcodeDao.update(moldingBarcode);
    }

    @Override
    public int updateAll(MoldingBarcodeDO moldingBarcode) {
        return moldingBarcodeDao.updateAll(moldingBarcode);
    }

    @Override
    public int remove(Long id) {
        return moldingBarcodeDao.remove(id);
    }

    @Override
    public int batchRemove(Long[] ids) {
        return moldingBarcodeDao.batchRemove(ids);
    }

    @Override
    public Map<String, Object> getById(Long id) {
        return null;
    }


    @Override
    public R pageList(MoldingBarcodePageParam pageParam) {
        List<MoldingBarcodeResultVO> moldingBarcodeResultVOS = new ArrayList<>();
        try {
            moldingBarcodeResultVOS = signPullTag(pageParam);
            return R.ok(200, "ok", moldingBarcodeResultVOS);
        } catch (Exception e) {
            return R.ok(500, e.getMessage(), null);
        }
    }

    public List<MoldingBarcodeResultVO> signPullTag(MoldingBarcodePageParam pageParam) {
        List<MoldingBarcodeResultVO> moldingBarcodeResultVOS = moldingBarcodeDao.selectMoldingList(pageParam);
        if (!CollectionUtils.isEmpty(moldingBarcodeResultVOS)) {
            List<Long> ids = new ArrayList<>();
            moldingBarcodeResultVOS.forEach(aa -> {
                ids.add(aa.getId());
            });
            List<MoldingBarcodeDO> moldingBarcodeDOS = moldingBarcodeDao.selectBYIds(ids);
            if (!CollectionUtils.isEmpty(moldingBarcodeDOS)) {
                Date date = new Date();
                moldingBarcodeDOS.forEach(aa -> {
                    //拉取状态 1 已拉取 0 未拉取
                    aa.setPullStatus(1);
                    aa.setPullTime(date);
                    aa.setPullStatus(1);
                });
                moldingBarcodeDao.batchUpdate(moldingBarcodeDOS);
            }
        }
        return moldingBarcodeResultVOS;
    }

    /**
     * 处理码枪返回的消息
     *
     * @param pageParam
     * @return
     */
    @Override
    public R callBackByParam(MoldingBarcodePageParam pageParam) {
        Long[] ids = pageParam.getIds();
        if (ids.length < 1 || ids == null) {
            return R.ok(500, "ids参数为空", null);
        } else {
            try {
                return signCallBackSucceed(ids);
            } catch (Exception e) {
                return R.ok(500, "工业互联返回标记异常，稍后重试，或联系开发", null);
            }
        }
    }

    public R signCallBackSucceed(Long[] ids) {
        List<Long> idAll = Arrays.asList(ids);
        List<MoldingBarcodeDO> moldingBarcodeDOS = moldingBarcodeDao.selectBYIds(idAll);
        if (!CollectionUtils.isEmpty(moldingBarcodeDOS)) {
            Date date = new Date();
            moldingBarcodeDOS.forEach(aa -> {
                aa.setCallBackTime(date);
                //码枪已打印状态 NG 1 OR PASS 2
                aa.setStatus(2);
            });
            moldingBarcodeDao.batchUpdate(moldingBarcodeDOS);
            return R.ok(200, "OK", null);
        } else {
            return R.ok(500, "根据返回主键未查到已拉取的数据", null);
        }
    }


    /**
     * 异步保存 打码枪信息
     *
     * @param dailyId 日志主键
     * @param mpiId   指示书主键
     * @param qty     数量
     * @param sign    1 成型日报   2  组装日报4
     * @param mGroup  组别
     */
    @Async("createPDFExecutor")
    @Override
    public void creatMoldingBarcode(Long dailyId, Long mpiId, BigDecimal qty, int mGroup, int sign, Date createTime) {
        List<MoldingBarcodeDO> moldingBarcodeDOAll = new ArrayList<>();
        try {
            switch (sign) {
                case 1:
                    //成型日报
                    //根据 mpiId  指示书主键  获取物料主键
//                MaterialVO materialMolding = moldingBarcodeDao.selectMolding(mpiId);
                    MaterialVO materialMolding = moldingBarcodeDao.selectMolding(dailyId);
                    //获取编号
                    List<Pair<Long, String>> listLongPair = generatingStreamCode(qty.intValue(), mGroup, materialMolding.getName(), createTime);
                    assemblyDataAndSave(dailyId, qty, listLongPair, materialMolding.getMaterielId(), createTime, true);
                    break;
                case 2:
                    //组装日报
//                    MaterialVO materialAssembly = moldingBarcodeDao.selectAssembly(mpiId);
                    MaterialVO materialAssembly = moldingBarcodeDao.selectAssembly2(dailyId);
                    //获取编号
                    log.error("qty:"+qty);
                    log.error("mGroup:"+mGroup);
                    log.error("materialAssembly:"+materialAssembly);
                    log.error("materialAssembly.getName:"+materialAssembly.getName());
                    log.error("createTime:"+createTime);
                    List<Pair<Long, String>> listLongPairAssembly = generatingStreamCode(qty.intValue(), mGroup, materialAssembly.getName(), createTime);
                    assemblyDataAndSave(dailyId, qty, listLongPairAssembly, materialAssembly.getMaterielId(), createTime, false);
                    break;
                default:
                    break;
            }
        }catch (Exception e) {
            e.printStackTrace();
            log.error(e.getMessage(),e);
            throw e;
        }

    }

    public void assemblyDataAndSave(Long dailyId, BigDecimal qty, List<Pair<Long, String>> listLongPairAssembly, Long materialId, Date createTime, Boolean sign) {
        List<MoldingBarcodeDO> moldingBarcodeDOAll = new ArrayList<>();
        for (int i = 0; i < listLongPairAssembly.size(); i++) {
            Pair<Long, String> longStringPair = listLongPairAssembly.get(i);
            MoldingBarcodeDO vo = new MoldingBarcodeDO();
            if (sign) {
                vo.setMoldingDailyId(dailyId);
                vo.setType(1);
            } else {
                vo.setAddemblyDailyId(dailyId);
                vo.setType(0);
            }
            vo.setMaterielId(materialId);
            vo.setTotalQty(qty);
            vo.setLotNo(longStringPair.getRight());
            vo.setSerialNo((longStringPair.getLeft().intValue()));
            vo.setCreateTime(createTime);
            vo.setPullStatus(0);
            moldingBarcodeDOAll.add(vo);
        }
        moldingBarcodeDao.batchSave(moldingBarcodeDOAll);
    }

    /**
     * @param count 本次要新增的数量
     * @return
     */
    public List<Pair<Long, String>> generatingStreamCode(int count, int mGroup, String materialName, Date createTime) {
//        产品名称-data-班次-流水号（001三位数字）；例: 产品名-20210909-A-999
        // 根据日期 查询 asl_molding_barcode 出最大已编 的序列号\
        String date = DateUtils.formatToString(createTime);
        String mGroupName = Objects.equals(mGroup, 1) ? "A" : Objects.equals(mGroup, 2) ? "B" : Objects.equals(mGroup, 3) ? "C" : "";
        String prefix = "";
        if (StringUtils.isNotBlank(mGroupName)) {
            prefix = materialName + "-" + date + "-" + mGroupName + "-";
        } else {
            prefix = materialName + "-" + date + "-";
        }
        //查询出今天最大流水号
        long valMax = moldingBarcodeDao.selectMoldingMax(createTime);
        count = 50;
        List<Pair<Long, String>> result = new ArrayList<>();
        int size = 4;
        for (int ii = 1; ii <= count; ii++) {
            valMax = valMax + 1;
            StringBuilder sb = new StringBuilder();
            sb.append(valMax);
            if (sb.length() < size) {
                int cnt = size - sb.length();
                for (int i = 0; i < cnt; i++) {
                    sb.insert(0, "0");
                }
                result.add(Pair.of(valMax, prefix + sb.toString()));
            } else if (sb.length() > size) {
                result.add(Pair.of(valMax, prefix + sb.toString()));
            } else {
                result.add(Pair.of(valMax, prefix + sb.toString()));
            }
        }
        return result;
    }


    @Autowired
    private ProductionPlanService productionPlanService;
    @Autowired
    private MaterielService materielService;


    /**
     * 码枪对接修改 22.7.06
     *
     * @param pageParam
     * @return
     */
    @Synchronized
    @Override
    public R callBackOfCode(String pageParam) {
        if (StringUtils.isNotBlank(pageParam)) {
            List<CodeGunNewVo> codeGunVos = JSONArray.parseArray(pageParam, CodeGunNewVo.class);
            HashMap<String, Object> hashMap = new HashMap<>();
            List<Long> materielIds = codeGunVos.stream().map(CodeGunNewVo::getMaterielId).collect(Collectors.toList());
            hashMap.put("ids",materielIds);
            List<MaterielDO> materielDOS = materielService.list(hashMap);
            Map<Long, MaterielDO> materielGroupById = materielDOS.stream().collect(Collectors.toMap(MaterielDO::getId, v -> v));
            if (!CollectionUtils.isEmpty(codeGunVos)) {
                if (codeGunVos.size() > 1) {
                    return R.error("只支持一条码枪信息接入！");
                }
                CodeGunNewVo codeGunNewVo = codeGunVos.get(0);
                if (Objects.isNull(codeGunNewVo.getMaterielId()) || Objects.isNull(codeGunNewVo.getLotNo())) {
                    return R.error("物料主键、LotNo 必填！");
                }
                //根据uuid校验是否重复  拿出重复值返回调用方
                List<String> lotNoOfList = new ArrayList<>();
                lotNoOfList.add(codeGunNewVo.getLotNo());
                //查出已保存过的
//                Boolean booleanListPair = this.lotNoOfAlreadyExist(lotNoOfList);
//                Map<Long, List<CodeGunNewVo>> codeGunVosOrderByMaterielId = codeGunVos.stream().collect(Collectors.groupingBy(CodeGunNewVo::getMaterielId));
//                if (booleanListPair) {
                //编码会重复，所以取消编码重复校验
                    MaterielDO materiel = materielGroupById.get(codeGunNewVo.getMaterielId());
                    AslBarCodeDO codeDO = new AslBarCodeDO();
                    codeDO.setStatus(0);
//                    codeDO.setBagging(0);
                    //默认已套袋，并且把页面的套袋按钮注释掉了
                    codeDO.setSeriesNumber(codeGunNewVo.getLotNo());
                    codeDO.setBatchNo(codeGunNewVo.getLotNo());
                    codeDO.setScrapStatus(0);
                    if (!ObjectUtils.isEmpty(materiel)){
                        codeDO.setProductCode(ObjectUtils.isEmpty(materiel.getSerialNo()) ? null : materiel.getSerialNo().toString());
                        codeDO.setBagging(1);
                        codeDO.setProductName(materiel.getName());
                        codeDO.setSpecificatio(materiel.getSpecification());
                        codeDO.setProductModel(materiel.getSpecification());
                    }else {
//                        codeDO.setProductCode(ObjectUtils.isEmpty(materiel.getSerialNo()) ? null : materiel.getSerialNo().toString());
                        codeDO.setBagging(0);
                        codeDO.setProductName(codeGunNewVo.getMaterielName());
                        codeDO.setSpecificatio(codeGunNewVo.getSpecification());
                        codeDO.setProductModel(codeGunNewVo.getSpecification());
                    }
                    codeDO.setLotNo(codeGunNewVo.getLotNo());
                    codeDO.setTrayId(AslConstant.ZERO.longValue());
                    codeDO.setProductId(codeGunNewVo.getMaterielId());
                    codeDO.setDelFlag(0);
                    codeDO.setCompanyName(codeGunNewVo.getCompanyName());
                    codeDO.setProductName(codeGunNewVo.getMaterielName());
//                    codeDO.setProductName(codeGunNewVo.getMaterielName());
                    codeDO.setInspeetor(codeGunNewVo.getInspeetor());
                    try {
                        codeDO.setBillDate(org.apache.commons.lang3.time.DateUtils.parseDate(codeGunNewVo.getDateTime(),"yyyy.MM.dd"));
                    } catch (ParseException e) {
                        e.printStackTrace();
                    }
//                    codeDO.setBillDate(dealDateFormatOfNow(codeGunNewVo.getDateTime()));
                    //匹配生产计划
                    return this.matchingProductionPlan(codeDO);
//                }else{
//                    return R.error("编码重复操作失败，重复编码:"+codeGunNewVo.getLotNo());
//                }
            }
        }
        return R.error("数据为空操作失败！");
    }

    private Date dealDateFormatOfNow(String nowDateStr) {
        try {
            SimpleDateFormat dateParser = new SimpleDateFormat("yyyy.MM.dd");
            Date parse = dateParser.parse(nowDateStr);
            return parse;
        } catch (Exception e) {
        }
        return null;
    }

    private R matchingProductionPlan(AslBarCodeDO insertDO) {
        List<ProductionPlanDO> countByMaterielId = productionPlanService.getCountByMaterielId(insertDO.getProductId());
//        if (!CollectionUtils.isEmpty(countByMaterielId)) {
            //回填
            if (!ObjectUtils.isEmpty(countByMaterielId)){
                log.error("无法匹配生产计划！请检查同物料生产计划是否存在！");
                ProductionPlanDO productionPlanDO = countByMaterielId.get(0);
//                productionPlanDO.setLotNoCount(productionPlanDO.getLotNoCount().add(BigDecimal.ONE));
                BigDecimal lotNoCount = ObjectUtils.isEmpty(productionPlanDO.getLotNoCount()) ? BigDecimal.ZERO : productionPlanDO.getLotNoCount();
                productionPlanDO.setLotNoCount(lotNoCount.add(BigDecimal.ONE));

                //放入生产计划id 并保存码枪信息
                insertDO.setUuid(productionPlanDO.getId());
                insertDO.setProductionPlanNo(productionPlanDO.getPlanNo());
                insertDO.setBagging(0);
                //更新生产计划
                List<ProductionPlanDO> saveVo = new ArrayList<>();
                saveVo.add(productionPlanDO);
                productionPlanService.batchUpdateForLotNo(saveVo);
            }
            aslBarCodeService.save(insertDO);
            return R.ok("操作成功！");
//        }else{
//            insertDO.setBagging(0);
//            aslBarCodeService.save(insertDO);
//            return R.error("无法匹配生产计划！请检查同物料生产计划是否存在！");
//        }
    }

    @Override
    public R listProduction(HashMap<String, Object> planMap) {
        List<ProductionPlanDO> resultList = productionPlanService.listProduction(planMap);
        Map<String, Object> result = Maps.newHashMap();
        int total = productionPlanService.countProduction(planMap);
        result.put("data", new DsResultResponse((Integer) planMap.get("pageno"),(Integer)planMap.get("pagesize"),total,resultList));
        return R.ok(result);
    }


    public Boolean lotNoOfAlreadyExist(List<String> lotNoOfList) {
        List<Map<String, Object>> codeByUuid = aslBarCodeService.getCodeByUuid(lotNoOfList);
        System.out.println("-----------------" +codeByUuid);
        if (!CollectionUtils.isEmpty(codeByUuid)) {
            return false;
        }
        return true;
    }




}
